/*  This file is part of -_-.

    -_- is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    -_- is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with -_-.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2012-2013 Oliver Katz */

#include "parser.h"

namespace sleepyface
{
	namespace opal
	{
		AST::AST()
		{
		}

		AST::AST(Token r)
		{
			root = r;
		}

		AST::AST(Token r, vector<AST> b)
		{
			root = r;
			branches = b;
		}

		int AST::branch(AST a)
		{
			branches.push_back(a);
			return branches.size()-1;
		}

		bool AST::isLeaf()
		{
			return branches.empty();
		}

		Token AST::get()
		{
			return root;
		}

		vector<AST> AST::getBranches()
		{
			return branches;
		}

		string AST::display()
		{
			if (!branches.empty())
			{
				stringstream ss;
				ss << "('" << root.get() << "'";
				for (vector<AST>::iterator i = branches.begin(); i != branches.end(); i++)
				{
					ss << " " << i->display();
				}
				ss << ")";
				return ss.str();
			}
			else
			{
				return "'"+root.get()+"'";
			}
		}

		string load(string path)
		{
			z_freader reader = z_freader_init((char *)path.c_str(), Z_FIO_WHOLE);
			if (!z_freader_ok(&reader))
				return "";
			z_data buf = z_freader_read(&reader);
			z_freader_release(reader);
			return string((const char *)z_data_src_get(&buf));
		}

		Parser::Parser()
		{
			leftSExpr = "(";
			rightSExpr = ")";
		}

		Parser::Parser(string l, string r)
		{
			leftSExpr = l;
			rightSExpr = r;
		}

		AST Parser::parse(vector<Token> page, string file)
		{
			int n = 0;
			int start = -1;

			AST rtn;

			for (int i = 0; i < page.size(); i++)
			{
				if (page[i].get().compare(leftSExpr) == 0)
				{
					if (n == 0)
						start = i;
					n++;
				}
				else if (page[i].get().compare(rightSExpr) == 0)
				{
					n--;
					if (n == 0)
					{
						vector<Token> subpage(page.begin()+(start+1), page.begin()+i);
						rtn.branch(parse(subpage, file));
					}
				}
				else
				{
					if (n == 0)
					{
						if (rtn.get().get().empty() && rtn.isLeaf())
							rtn = AST(page[i]);
						else
							rtn.branch(AST(page[i]));
					}
				}
			}

			if (rtn.getBranches().size() == 1 && rtn.get().get().empty())
			{
				rtn = rtn.getBranches()[0];
			}

			if (n != 0)
			{
				error(page[0], file, "parenthesis don't match up");
			}
			else if (rtn.get().get().empty())
			{
				error(page[0], file, "cannot start an expression with another expression - ((A B) C)");
			}

			return rtn;
		}

		string findImportPath(vector<string> path, string mod, Token dbg, string file)
		{
			for (vector<string>::iterator i = path.begin(); i != path.end(); i++)
			{
				string tmp = *i+"/"+mod+".opal";
				FILE *f = fopen(tmp.c_str(), "r");
				if (f != NULL)
				{
					fclose(f);
					return tmp;
				}
			}

			error(dbg, file, "can't find module "+mod);
			return "";
		}

		AST loadAndParse(string path, Lexer l, Parser p, vector<string> ipath)
		{
			string page = load(path);
			vector<Token> toks = l.lex(page, path);
			AST ast = p.parse(toks, path);
			ast = handleAllImports(ast, "import", l, p, ipath, path);
			return ast;
		}

		AST handleAllImports(AST ast, string it, Lexer l, Parser p, vector<string> path, string file)
		{
			if (ast.get().get().compare(it) == 0)
			{
				string ipath = findImportPath(path, ast.getBranches()[0].get().get(), ast.get(), file);
				return loadAndParse(ipath, l, p, path);
			}
			else
			{
				AST tmp = AST(ast.get());
				vector<AST> b = ast.getBranches();
				for (vector<AST>::iterator i = b.begin(); i != b.end(); i++)
				{
					tmp.branch(handleAllImports(*i, it, l, p, path, file));
				}
				return tmp;
			}
		}
	}
}
